package com.Redblue;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

public class Redblue {
	
	//-----------------------------------------------------------------
	//添加对某个变量的监听，第一个参数是变量名，第二个是变量改变前的值，第二个是变量改变后的值
	private final PropertyChangeSupport propertyChanges = 
			        new PropertyChangeSupport(this);
    private int propertyState = 0;
    
	private volatile int msDemoStep = 200;
	private volatile boolean toStop = false;
	// 标准围棋 19 路，棋子在格子线交叉处
	private int nRow = 19;
	private int nCol = 19;

	private final int RedActive = 1;
	private final int BlueActive = 2;
	private final int RedDead = 41;
	private final int BlueDead = 42;
	
	// 赋值 红子 1， 蓝子 2，无子 0, 死红 41，死蓝 42
	private int[][] gameCells1 = new int[nRow][nCol];
	// x=int[0], y=int[1]
	private int[] nextMove = new int[2];
	private Random rnd = new Random();
	
	// 一个点的8个临近点坐标(一层周边, 第k层周边：k*nb8[x][y])
	private int[][] nb8 = {
			{-1, 0},	// 左
			{ 1, 0},	// 右
			{ 0,-1},	// 上
			{ 0, 1},	// 下
			{-1,-1},	// 左上
			{-1, 1},	// 坐下
			{ 1,-1},	// 右上
			{ 1, 1}		// 右下
	};
	// 一个点的16个临近点坐标(两层周边)
	private int[][] nb16 = {
			{-1, 0},	// 左
			{ 1, 0},	// 右
			{ 0,-1},	// 上
			{ 0, 1},	// 下
			{-1,-1},	// 左上
			{-1, 1},	// 坐下
			{ 1,-1},	// 右上
			{ 1, 1},	// 右下			
			{-2, 0},	// 左
			{ 2, 0},	// 右
			{ 0,-2},	// 上
			{ 0, 2},	// 下
			{-2,-2},	// 左上
			{-2, 2},	// 坐下
			{ 2,-2},	// 右上
			{ 2, 2}		// 右下
	};

	
	//----------------------------- -----------------------------------
    public void addPropertyChangeListener(PropertyChangeListener listener) {
    	propertyChanges.addPropertyChangeListener(listener);
    	//System.out.println("addPropertyChangeLister: ");
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
    	propertyChanges.removePropertyChangeListener(listener);
    	//System.out.println("removePropertyChangeLister: ");
    }

    // 当需要通知 Listener 时，执行如下语句
    // propertyChanges.firePropertyChange(String propertyName, Object oldValue, Object newValue) {

	public static void main(String[] args) {
		Redblue rb = new Redblue();
		
	}
	
    public void resetDemoStep(int ms) {
    	msDemoStep = ms;
    	if (msDemoStep < 50)
    		msDemoStep = 50;
    	if (msDemoStep > 1000)
    		msDemoStep = 1000;
   
    	return; 
    }
    
    public void resetStopFlag(boolean bt) {
    	toStop = bt;
    	return; 
    }

	private void waitMS(int ms) {
		if( ms < 1)
			return;
		try {
			Thread.sleep(ms);
		} 
		catch (Exception e) {
			throw new RuntimeException("waitMS error: Thread.sleep");
		}		
	}

	// 启动线程
	public void startRedblueThread() {
		// 生成一个匿名线程 并开始执行
		new Thread() {
			public void run() {
				System.out.println("Redblue: Original Game ...");
				propertyChanges.firePropertyChange("Redblue", false, gameCells1);
				waitMS(900);
				waitMS(900);
				// 进入循环，游戏每一步的结果发送一次
				while(!toStop) {
					//List<List<Integer>> mat = new ArrayList<List<Integer>>(); //
					int[][] mat = getNextGame();
					// 发送中间结果
					propertyChanges.firePropertyChange("Redblue", false, mat);
					waitMS(msDemoStep);
					// 将进化状态返回给主程序，oldValue = status
					// 0, 未决胜负；1，红方赢了；2，蓝方赢了
					int status = isGameOver();
					if (status == 1) {
						propertyChanges.firePropertyChange("Redblue is over!", false, status);
						waitMS(msDemoStep);
						break;
					}
					else if(status == 2) {
						propertyChanges.firePropertyChange("Redblue is over!", false, status);
						waitMS(msDemoStep);
						break;
					}
						
				}// while
			} // end run
		}.start();
	}
	
	// 
	public Redblue() {
		super();
	}

	// 三种模式：sparse,seed=1, normal,seed=2, dense,seed=3
	public Redblue(int seed) {
		initGame(seed);
	}

	// 随机 生成指定个数的红蓝棋子 --> gameCells[][]
	// seed=1:50-100, seed=2:100-150, seed=3:150-200
	// 棋子总数以及红蓝棋子都是随机的
	private void initGame(int seed) {
		int total = nRow*nCol;
		int kx, ky;
		// 随机数 rn 属于[0, 50)
		int rn = rnd.nextInt(20);
		int nrb;
		if (seed == 1) {
			nrb = rn + 10;
		}
		else if (seed == 2) {
			nrb = rn + 20;
		}
		else if(seed == 3) {
			nrb = rn + 50;
		}
		else if(seed == 4) {
			nrb = rn + 100;			
		}
		else {
			nrb = rn + 2;
		}
		// 
		clearGame(gameCells1);
		// 下标不能相同
		Set<Integer> vset = new HashSet<Integer>();
		for(int i=0; i<nrb; i++) {
			rn = rnd.nextInt(total);
			if (vset.contains(rn)) {
				continue;
			}
			vset.add(rn);
			kx = rn/nCol;
			ky = rn%nCol;
			// 随机决定是红或者蓝
			rn = rnd.nextInt(100);
			// 红子 1， 蓝子 2，无子 0
			if (rn < 50) { // 红色棋子
				gameCells1[kx][ky] = RedActive;
			}
			else {  // 蓝色棋子
				gameCells1[kx][ky] = BlueActive;
			}
		}
	}

	// gameCells[][] = 1, 黑色; gameCells[][] = 0, 白色
	private void clearGame(int[][] gameCells) {
		for(int i=0; i<gameCells.length; i++) {
			for(int j=0; j<gameCells[0].length; j++) {
				gameCells[i][j] = 0;
			}
		}
	}

	// 吃子检查：两个或以上同样颜色的子与另一颜色的子相邻，多吃少
	private void hackDeadGame() {
		int k1, k2, k3, k4;
		int cv1, cv2;
		for(int i=0; i<nRow; i++) {
			for(int j=0; j<nCol; j++) {
				int cv = gameCells1[i][j];
				if (cv == RedDead || cv == BlueDead) {
					continue;
				}
				// 上下方向
				k1 = i-1;
				k2 = i+1;
				if (k1>=0 && k2<nRow) {
					cv1 = gameCells1[k1][j];
					cv2 = gameCells1[k2][j];
					if (cv1==cv2 && cv1==RedActive && cv==BlueActive) {
						gameCells1[i][j] = BlueDead;
					}
					else if (cv1==cv2 && cv1==BlueActive && cv==RedActive) {
						gameCells1[i][j] = RedDead;
					}					
				}
				// 左右方向
				k1 = j-1;
				k2 = j+1;
				if (k1>=0 && k2<nCol) {
					cv1 = gameCells1[i][k1];
					cv2 = gameCells1[i][k2];
					if (cv1==cv2 && cv1==RedActive && cv==BlueActive) {
						gameCells1[i][j] = BlueDead;
					}
					else if (cv1==cv2 && cv1==BlueActive && cv==RedActive) {
						gameCells1[i][j] = RedDead;
					}					
				}
				// 斜线方向 135度角
				k1 = i-1;
				k2 = j-1;
				k3 = i+1;
				k4 = j+1;
				if (k1>=0 && k2>=0 && k3<nRow && k4<nCol) {
					cv1 = gameCells1[k1][k2];
					cv2 = gameCells1[k3][k4];
					if (cv1==cv2 && cv1==RedActive && cv==BlueActive) {
						gameCells1[i][j] = BlueDead;
					}
					else if (cv1==cv2 && cv1==BlueActive && cv==RedActive) {
						gameCells1[i][j] = RedDead;
					}					
				}
				// 反斜线方向 45度角
				k1 = i-1;
				k2 = j+1;
				k3 = i+1;
				k4 = j-1;
				if (k1>=0 && k2<nCol && k3<nRow && k4>=0) {
					cv1 = gameCells1[k1][k2];
					cv2 = gameCells1[k3][k4];
					if (cv1==cv2 && cv1==RedActive && cv==BlueActive) {
						gameCells1[i][j] = BlueDead;
					}
					else if (cv1==cv2 && cv1==BlueActive && cv==RedActive) {
						gameCells1[i][j] = RedDead;
					}					
				}				
			} // for(j)
		} // for(i)
	
	}

	// 寻找下一步最好的位置
	private int[] findNextMove() {

		// x=int[0], y=int[1]
		return nextMove;
		
	}
	
	// 棋子各走一步, 生成新的棋局 gameCells1
	private void nextMoveGame() {
		// nextMove = findNextMove();
		int ik, jk;
		for(int i=0; i<gameCells1.length; i++) {
			for(int j=0; j<gameCells1[0].length; j++) {
				int cv = gameCells1[i][j];
				// 死棋子
				if (cv == RedDead || cv == BlueDead) {
					continue;
				}				
				// 单元格红色或蓝色棋子可以移动，白色或灰色的棋子不动
				if (cv == RedActive || cv == BlueActive) {
					// 随机选择一个运动方向：上下左右，不动
					int dir = rnd.nextInt(5);
					switch(dir) {
						case 0:	// 不动
							break;
						case 1:	// 上
							jk = j - 1;
							if (jk < 0)	jk = 0;
							if (gameCells1[i][jk] == 0) {
								gameCells1[i][jk] = cv;
								gameCells1[i][j] = 0;
							}
							break;
						case 2:	// 下
							jk = j + 1;
							if(jk > nCol-1)	jk = nCol-1;
							if (gameCells1[i][jk] == 0) {
								gameCells1[i][jk] = cv;
								gameCells1[i][j] = 0;
							}
							break;
						case 3:	// 左
							ik = i - 1;
							if (ik < 0)	ik = 0;
							if (gameCells1[ik][j] == 0) {
								gameCells1[ik][j] = cv;
								gameCells1[i][j] = 0;
							}
							break;
						case 4: // 右
							ik = i + 1;
							if (ik > nRow -1)	ik = nRow -1;
							if (gameCells1[ik][j] == 0) {
								gameCells1[ik][j] = cv;
								gameCells1[i][j] = 0;
							}
							break;
						default:// 不动
							break;
					} // switch
				} // if()
			} // for(j)
		} // for(i)
	
	}
	
	// 检查是否赢了: 0, 未决胜负；1，红方赢了；2，蓝方赢了
	public int isGameOver() {
		boolean tred = false;
		boolean tblue = false;
		for(int i=0; i<gameCells1.length; i++) {
			for(int j=0; j<gameCells1[0].length; j++) {
				int cv = gameCells1[i][j];
				// red 还有棋子
				if (cv == RedActive) {
					tred = true;
				}
				else if (cv == BlueActive) {
					tblue = true;
				}
			}
		}
		// 红方蓝方都有棋子，未分胜负
		if (tred && tblue) 			
			return 0;
		// 红方没有棋子，蓝方赢了
		else if (!tred && tblue) 			
			return 2;
		// 蓝方没有棋子，红方赢了
		else if (!tblue && tred) 			
			return 1;
		// 不能出现的情况
		else
			return 0;
	}
	
	// 
	public int[][] getNextGame() {
		hackDeadGame();
		//System.out.println("to fuckDead");
		nextMoveGame();
		return gameCells1;
	}

}
